package com.anlu.base;

import lombok.extern.slf4j.Slf4j;

import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;

/**
 * Hello world!
 *
 */
@Slf4j
public class App 
{
    private static final String ROCKET_LAUNCH_LOG_PATTERN = "Space rocket <%s> launched successfully";

    public static void main( String[] args ) throws InterruptedException, ExecutionException {
        System.out.println( "Hello World!" );

        var executor = new ThreadAsyncExecutor();

        final var asyncResult1 = executor.startProcess(lazyval(10, 500));
        final var asyncResult2 = executor.startProcess(lazyval("test", 300));
        final var asyncResult3 = executor.startProcess(lazyval(50L, 700));
        final var asyncResult4 = executor.startProcess(lazyval(20, 400),
                callback("Deploying lunar rover"));

        final var asyncResult5 = executor.startProcess(lazyval("callback", 600),
                callback("Deploying lunar rover"));

        Thread.sleep(350); // Oh boy, we are working hard here
        log("Mission command is sipping coffee");
//
//        // wait for completion of the tasks
        final var result1 = executor.endProcess(asyncResult1);
        final var result2 = executor.endProcess(asyncResult2);
        final var result3 = executor.endProcess(asyncResult3);
        asyncResult4.await();
        asyncResult5.await();
//
//        // log the results of the tasks, callbacks log immediately when complete
        log(String.format(ROCKET_LAUNCH_LOG_PATTERN, result1));
        log(String.format(ROCKET_LAUNCH_LOG_PATTERN, result2));
        log(String.format(ROCKET_LAUNCH_LOG_PATTERN, result3));
    }

    private static <T>Callable<T> lazyval(T value, long delayMillis){
        return () -> {
            Thread.sleep(delayMillis);
            log(String.format(ROCKET_LAUNCH_LOG_PATTERN, value));
            return value;
        };
    }

    private static <T> AsyncCallback<T> callback(String name){
        return new AsyncCallback<T>() {
            @Override
            public void
            onComplete(T value) {
                log(name + " <" + value + ">");
            }

            @Override
            public void onError(Throwable ex) {
                log(name + " failed: " + ex.getMessage());
            }
        };
    }

    private static void log(String msg) {
        log.info(msg);
    }
}
